﻿using System;
using System.Web;
using System.Collections.Generic;
using sBlog.Net.Domain.Entities;
using MemcachedProviders.Cache;
using sBlog.Net.Domain;
using sBlog.Net.Domain.Interfaces;

namespace sBlog.Net.Domain.Concrete
{
    public class MemcaheService : DefaultDisposable, IMemcaheService
    {
        private readonly IPost _postRepository;
        private readonly IUser _userRepository;
        private readonly ITag _tagReponsitory;
        private readonly IFollow _followReponsitory;
        private readonly ICategory _categoryReponsitory;

        public MemcaheService(IPost postRepository, IUser userRepository, ITag tagReponsitory, IFollow followReponsitory, ICategory categoryReponsitory)
        {
            _postRepository = postRepository;
            _userRepository = userRepository;
            _tagReponsitory = tagReponsitory;
            _followReponsitory = followReponsitory;
            _categoryReponsitory = categoryReponsitory;
        }

        public List<PostEntity> GetHomePageWithPage(int pageSize, int pageNumber)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetHomePageWithPage + pageNumber);
            if (obj == null)
            {
                postEntities = _postRepository.GetHomePageWithPage(pageSize, pageNumber);
                DistCache.Add(MemCacheKey.KeyGetHomePageWithPage + pageNumber, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public PostEntity GetPostByUrl(string url, byte entryType)
        {
            PostEntity post = new PostEntity();
            PostEntity obj = DistCache.Get<PostEntity>(MemCacheKey.KeyGetPostByUrl + url);
            if (obj == null)
            {
                post = _postRepository.GetPostByUrl(url, entryType);
                if (post != null)
                {
                    var user = this.GetUserObjByUserID(post.OwnerUserID);
                    post.Categories = this.GetCategoriesByPostID(post.PostID);
                    post.Tags = this.GetTagsByPostID(post.PostID);
                    post.OwnerUserName = user.UserDisplayName;
                    post.UserName = user.UserName;
                }
                DistCache.Add(MemCacheKey.KeyGetPostByUrl + url, post);
            }
            else
            {
                post = obj;
            }

            return post;
        }

        public List<PostEntity> GetMostPostByAuthors(int OwnerUserID, int currentPostID)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetMostPostByAuthors + OwnerUserID);
            if (obj == null)
            {
                postEntities = _postRepository.GetMostPostByAuthors(OwnerUserID, currentPostID);
                DistCache.Add(MemCacheKey.KeyGetMostPostByAuthors + OwnerUserID, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public List<PostEntity> GetPostWidgetHocMai(int numPost, string catslug)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostWidgetHocMai + numPost + "_" + catslug);
            if (obj == null)
            {
                postEntities = _postRepository.GetPostWidgetHocMai(numPost, catslug);
                DistCache.Add(MemCacheKey.KeyGetPostWidgetHocMai + numPost + "_" + catslug, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public List<PostEntity> ShowReadContentPage()
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyShowReadContentPage);
            if (obj == null)
            {
                postEntities = _postRepository.ShowReadContentPage();
                DistCache.Add(MemCacheKey.KeyShowReadContentPage, postEntities);
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public List<PostEntity> GetPostsByUserID(int userID)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostsByUserIDNoNeedentryType + userID);
            if (obj == null)
            {
                postEntities = _postRepository.GetPostsByUserID(userID);
                DistCache.Add(MemCacheKey.KeyGetPostsByUserIDNoNeedentryType + userID, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }

            return postEntities;
        }

        public List<PostEntity> GetPostRelateTag(int postID)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostRelateTag + postID);
            if (obj == null)
            {
                postEntities = _postRepository.GetPostRelateTag(postID);
                DistCache.Add(MemCacheKey.KeyGetPostRelateTag + postID, postEntities);
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }

            return postEntities;
        }

        public List<PostEntity> SearchKeywordWithPage(string textSearch, int? pageNumber, int? pageSize)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeySearchKeywordWithPage + textSearch + "_" + pageNumber);
            if (obj == null)
            {
                postEntities = _postRepository.SearchKeywordWithPage(textSearch, pageNumber, pageSize);
                DistCache.Add(MemCacheKey.KeySearchKeywordWithPage + textSearch + "_" + pageNumber, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }

            return postEntities;
        }

        public List<PostEntity> GetPostsByUserIdWithPage(int userId, int? pageNumber, int? pageSize)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostsByUserIdWithPage + userId + "_" + pageNumber);
            if (obj == null)
            {
                postEntities = _postRepository.GetPostsByUserIdWithPage(userId, pageNumber, pageSize);
                DistCache.Add(MemCacheKey.KeyGetPostsByUserIdWithPage + userId + "_" + pageNumber, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }

            return postEntities;
        }

        public List<PostEntity> GetMostViewPostByCatSlug(string catslug)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetMostViewPostByCatSlug + catslug);
            if (obj == null)
            {
                postEntities = _postRepository.GetMostViewPostByCatSlug(catslug);
                DistCache.Add(MemCacheKey.KeyGetMostViewPostByCatSlug + catslug, postEntities);
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public int GetTotalViewPostByUserId(int userID)
        {
            int TotalViewPost = 0;
            int obj = DistCache.Get<int>(MemCacheKey.KeyGetTotalViewPostByUserId + userID);
            if (obj == 0)
            {
                TotalViewPost = _postRepository.GetTotalViewPostByUserId(userID);
                DistCache.Add(MemCacheKey.KeyGetTotalViewPostByUserId + userID, TotalViewPost);
            }
            else
            {
                TotalViewPost = obj;
            }
            return TotalViewPost;
        }

        public int GetTotalLikePostByUserId(int userID)
        {
            int TotalLikePost = 0;
            int obj = DistCache.Get<int>(MemCacheKey.KeyGetTotalLikePostByUserId + userID);
            if (obj == 0)
            {
                TotalLikePost = _postRepository.GetTotalLikePostByUserId(userID);
                DistCache.Add(MemCacheKey.KeyGetTotalLikePostByUserId + userID, TotalLikePost);
            }
            else
            {
                TotalLikePost = obj;
            }
            return TotalLikePost;
        }

        public List<PostEntity> GetPosts(int userID)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostsByUserID);

            if (obj == null)
            {
                postEntities = _postRepository.GetPosts(userID);
                DistCache.Add(MemCacheKey.KeyGetPostsByUserID, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }

            return postEntities;
        }

        public List<PostEntity> GetPostsByUserID(int userID, byte entryType)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostsByUserIDNeedentryType + userID);

            if (obj == null)
            {
                postEntities = _postRepository.GetPostsByUserID(userID, entryType);
                DistCache.Add(MemCacheKey.KeyGetPostsByUserIDNeedentryType + userID, postEntities);
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }

            return postEntities;
        }

        public List<PostEntity> GetNewPostByAuthor(int ownerUserID)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetNewPostByAuthor + ownerUserID);

            if (obj == null)
            {
                postEntities = _postRepository.GetNewPostByAuthor(ownerUserID);
                DistCache.Add(MemCacheKey.KeyGetNewPostByAuthor + ownerUserID, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public List<PostEntity> GetPostFeature()
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostFeature);
            if (obj == null)
            {
                postEntities = _postRepository.GetPostFeature();
                DistCache.Add(MemCacheKey.KeyGetPostFeature, postEntities);
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public IEnumerable<PostEntity> GetNewPosts()
        {
            IEnumerable<PostEntity> postEntities;
            object obj = DistCache.Get(MemCacheKey.KeyGetNewPosts);
            if (obj == null)
            {
                postEntities = _postRepository.GetNewPosts();
                DistCache.Add(MemCacheKey.KeyGetNewPosts, postEntities);
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public List<PostEntity> GetPostsByTagWithPage(string tagSlug, int pageSize, int pageNumber)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostsByTagWithPage + tagSlug + "_" + pageSize + "_" + pageNumber);
            if (obj == null)
            {
                postEntities = _postRepository.GetPostsByTagWithPage(tagSlug, pageSize, pageNumber);
                DistCache.Add(MemCacheKey.KeyGetPostsByTagWithPage + tagSlug + "_" + pageSize + "_" + pageNumber, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public List<PostEntity> GetPostsByCategoryWithPage(string catSlug, int pageSize, int pageNumber)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostsByCategoryWithPage + catSlug + "_" + pageSize + "_" + pageNumber);
            if (obj == null)
            {
                postEntities = _postRepository.GetPostsByCategoryWithPage(catSlug, pageSize, pageNumber);
                DistCache.Add(MemCacheKey.KeyGetPostsByCategoryWithPage + catSlug + "_" + pageSize + "_" + pageNumber, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public List<PostEntity> GetMostViewPostByCatSlugAndOwnerUserID(int ownerUserID, string catSlug)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetMostViewPostByCatSlugAndOwnerUserID + ownerUserID + "_" + catSlug);
            if (obj == null)
            {
                postEntities = _postRepository.GetMostViewPostByCatSlugAndOwnerUserID(ownerUserID, catSlug);
                DistCache.Add(MemCacheKey.KeyGetMostViewPostByCatSlugAndOwnerUserID + ownerUserID + "_" + catSlug, PostProcessEntities(postEntities));
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }
            return postEntities;
        }

        public PostEntity GetPostByID(int postID)
        {
            PostEntity post = new PostEntity();
            PostEntity obj = DistCache.Get<PostEntity>(MemCacheKey.KeyGetPostByID + postID);
            if (obj == null)
            {
                post = _postRepository.GetPostByID(postID);
                if (post != null)
                {
                    var user = this.GetUserObjByUserID(post.OwnerUserID);
                    post.Categories = this.GetCategoriesByPostID(post.PostID);
                    post.Tags = this.GetTagsByPostID(post.PostID);
                    post.OwnerUserName = user.UserDisplayName;
                    post.UserName = user.UserName;
                }
                DistCache.Add(MemCacheKey.KeyGetPostByID + postID, post);
            }
            else
            {
                post = obj;
            }
            return post;
        }

        public void UpdateViewCount(int postID)
        {
            _postRepository.UpdateViewCount(postID);
        }

        /// 

        ///User
        public List<UserEntity> GetAllUsersPromote(Boolean isPromote)
        {
            List<UserEntity> lstUser;
            object obj = DistCache.Get(MemCacheKey.KeyGetAllUsersPromote);

            if (obj == null)
            {
                lstUser = _userRepository.GetAllUsersPromote(isPromote);
                foreach (UserEntity user in lstUser)
                {
                    user.TotalPost = this.GetPostsByUserID(user.UserID).Count;
                    user.TotalViewPost = this.GetTotalViewPostByUserId(user.UserID);
                }
                DistCache.Add(MemCacheKey.KeyGetAllUsersPromote, lstUser);
            }
            else
            {
                lstUser = (List<UserEntity>)obj;
            }
            return lstUser;
        }

        public UserEntity GetUserObjByUserName(string userName)
        {
            UserEntity user;
            object obj = DistCache.Get(MemCacheKey.KeyGetUserObjByUserName + userName);
            if (obj == null)
            {
                user = _userRepository.GetUserObjByUserName(userName);
                DistCache.Add(MemCacheKey.KeyGetUserObjByUserName + userName, user);
            }
            else
            {
                user = (UserEntity)obj;
            }
            return user;
        }

        public IEnumerable<UserEntity> GetListMlogFace()
        {
            IEnumerable<UserEntity> lstUser;
            object obj = DistCache.Get(MemCacheKey.KeyGetListMlogFace);

            if (obj == null)
            {
                lstUser = _userRepository.GetListMlogFace();
                DistCache.Add(MemCacheKey.KeyGetListMlogFace, lstUser);
            }
            else
            {
                lstUser = (IEnumerable<UserEntity>)obj;
            }

            return lstUser;
        }

        public UserEntity GetUserObjByUserID(int userID)
        {
            UserEntity userEntity = new UserEntity();
            object obj = DistCache.Get(MemCacheKey.KeyGetUserObjByUserID + userID);
            if (obj == null)
            {
                userEntity = _userRepository.GetUserObjByUserID(userID);
                DistCache.Add(MemCacheKey.KeyGetUserObjByUserID + userID, userEntity);
            }
            else
            {
                userEntity = (UserEntity)obj;
            }

            return userEntity;
        }

        public List<PostEntity> GetPages(int userID)
        {
            List<PostEntity> postEntities = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPages + userID);
            if (obj == null)
            {
                postEntities = _postRepository.GetPages(userID);
                DistCache.Add(MemCacheKey.KeyGetPages + userID, postEntities);
            }
            else
            {
                postEntities = (List<PostEntity>)obj;
            }

            return postEntities;
        }

        ///

        ///Tag
        public List<TagEntity> MostTagPosts()
        {
            List<TagEntity> model = new List<TagEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyMostTagPosts);
            if (obj == null)
            {
                model = _tagReponsitory.GetMostTags();
                DistCache.Add(MemCacheKey.KeyMostTagPosts, model);
            }
            else
            {
                model = (List<TagEntity>)obj;
            }

            return model;
        }

        public List<TagEntity> GetTagsByPostID(int postID)
        {
            var tagEntities = new List<TagEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetTagsByPostID + postID);
            if (obj == null)
            {
                tagEntities = _tagReponsitory.GetTagsByPostID(postID);
                DistCache.Add(MemCacheKey.KeyGetTagsByPostID + postID, tagEntities);
            }
            else
            {
                tagEntities = (List<TagEntity>)obj;
            }

            return tagEntities;
        }

        public List<TagEntity> GetTagEntityByTagSlug(string tagSlug)
        {
            List<TagEntity> model = new List<TagEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetTagEntityByTagSlug + tagSlug);
            if (obj == null)
            {
                model = _tagReponsitory.GetTagEntityByTagSlug(tagSlug);
                DistCache.Add(MemCacheKey.KeyGetTagEntityByTagSlug + tagSlug, model);
            }
            else
            {
                model = (List<TagEntity>)obj;
            }

            return model;
        }

        ///

        ///Follow
        public List<FollowEntity> GetFollowByFollowingUserID(int followingUserID)
        {
            List<FollowEntity> followEntity = new List<FollowEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetFollowByFollowingUserID + followingUserID);
            if (obj == null)
            {
                followEntity = _followReponsitory.GetFollowByFollowingUserID(followingUserID);
                DistCache.Add(MemCacheKey.KeyGetFollowByFollowingUserID + followingUserID, followEntity);
            }
            else
            {
                followEntity = (List<FollowEntity>)obj;
            }

            return followEntity;
        }

        public List<FollowEntity> GetFollowByFollowerUserID(int followerUserID)
        {
            List<FollowEntity> followEntity = new List<FollowEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetFollowByFollowerUserID + followerUserID);
            if (obj == null)
            {
                followEntity = _followReponsitory.GetFollowByFollowerUserID(followerUserID);
                DistCache.Add(MemCacheKey.KeyGetFollowByFollowerUserID + followerUserID, followEntity);
            }
            else
            {
                followEntity = (List<FollowEntity>)obj;
            }
            return followEntity;
        }

        public List<PostEntity> PostProcessEntities(List<PostEntity> postEntities)
        {
            postEntities.ForEach(p =>
            {
                //p.Comments = _commentRepository.GetCommentsByPostID(p.PostID);
                p.Categories = this.GetCategoriesByPostID(p.PostID);
                p.Tags = this.GetTagsByPostID(p.PostID);

                var user = this.GetUserObjByUserID(p.OwnerUserID);
                p.OwnerUserName = user.UserDisplayName;
                p.UserName = user.UserName;
                p.UserAvatar = user.Avatar;
            });
            return postEntities;
        }


        public List<PostEntity> GetPostsByUserIDAndStatusForCP(int userID, int status, byte entryType)
        {
            List<PostEntity> lstPost = new List<PostEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetPostsByUserIDAndStatusForCP + userID + "_" + status + "_" + entryType);
            if (obj == null)
            {
                lstPost = _postRepository.GetPostsByUserIDAndStatusForCP(userID, status, entryType);
                DistCache.Add(MemCacheKey.KeyGetPostsByUserIDAndStatusForCP + userID + "_" + status + "_" + entryType, lstPost);
            }
            else
            {
                lstPost = (List<PostEntity>)obj;
            }
            return lstPost;
        }

        ///

        ///Category
        public List<CategoryEntity> GetCategoryEntityByCategorySlug(string catSlug)
        {
            List<CategoryEntity> followEntity = new List<CategoryEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetCategoryEntityByCategorySlug + catSlug);
            if (obj == null)
            {
                followEntity = _categoryReponsitory.GetCategoryEntityByCategorySlug(catSlug);
                DistCache.Add(MemCacheKey.KeyGetCategoryEntityByCategorySlug + catSlug, followEntity);
            }
            else
            {
                followEntity = (List<CategoryEntity>)obj;
            }
            return followEntity;
        }

        public List<CategoryEntity> GetCategoriesByPostID(int postID)
        {
            List<CategoryEntity> lstCategory = new List<CategoryEntity>();
            object obj = DistCache.Get(MemCacheKey.KeyGetCategoriesByPostID + postID);
            if (obj == null)
            {
                lstCategory = _categoryReponsitory.GetCategoriesByPostID(postID);
                DistCache.Add(MemCacheKey.KeyGetCategoriesByPostID + postID, lstCategory);
            }
            else
            {
                lstCategory = (List<CategoryEntity>)obj;
            }
            return lstCategory;
        }

        ///

        ~MemcaheService()
        {
            Dispose(false);
        }
    }
}
